<template>
  <div
    v-show="value"
    v-loading.fullscreen.lock="fullscreenLoading"
    class="vue-image-crop-upload"
    element-loading-text="正在处理图片中请骚等"
    element-loading-background="rgba(255, 255, 255, 0.8)"
  >
    <div class="vicp-wrap">
      <div class="vicp-close" @click="off">
        <i class="vicp-icon4" />
      </div>

      <div v-show="step == 1" class="vicp-step1">
        <div class="vicp-drop-area" @dragleave="preventDefault" @dragover="preventDefault" @dragenter="preventDefault" @click="handleClick" @drop="handleChange">
          <i v-show="loading != 1" class="vicp-icon1">
            <i class="vicp-icon1-arrow" />
            <i class="vicp-icon1-body" />
            <i class="vicp-icon1-bottom" />
          </i>
          <span v-show="loading !== 1" class="vicp-hint">{{ lang.hint }}</span>
          <span v-show="!isSupported" class="vicp-no-supported-hint">{{ lang.noSupported }}</span>
          <input v-show="false" v-if="step == 1" ref="fileinput" type="file" @change="handleChange">
        </div>
        <div v-show="hasError" class="vicp-error">
          <i class="vicp-icon2" /> {{ errorMsg }}
        </div>
        <div class="vicp-operate">
          <a @click="off" @mousedown="ripple">{{ lang.btn.off }}</a>
        </div>
      </div>

      <div v-if="step == 2" class="vicp-step2">
        <div class="vicp-crop">
          <div v-show="true" class="vicp-crop-left">
            <div class="vicp-img-container">
              <img
                ref="img"
                :src="sourceImgUrl"
                :style="sourceImgStyle"
                class="vicp-img"
                draggable="false"
                @drag="preventDefault"
                @dragstart="preventDefault"
                @dragend="preventDefault"
                @dragleave="preventDefault"
                @dragover="preventDefault"
                @dragenter="preventDefault"
                @drop="preventDefault"
                @touchstart="imgStartMove"
                @touchmove="imgMove"
                @touchend="createImg"
                @touchcancel="createImg"
                @mousedown="imgStartMove"
                @mousemove="imgMove"
                @mouseup="createImg"
                @mouseout="createImg"
              >
              <div :style="sourceImgShadeStyle" class="vicp-img-shade vicp-img-shade-1" />
              <div :style="sourceImgShadeStyle" class="vicp-img-shade vicp-img-shade-2" />
            </div>

            <div class="vicp-range">
              <input :value="scale.range" type="range" step="1" min="0" max="100" @input="zoomChange">
              <i class="vicp-icon5" @mousedown="startZoomSub" @mouseout="endZoomSub" @mouseup="endZoomSub" />
              <i class="vicp-icon6" @mousedown="startZoomAdd" @mouseout="endZoomAdd" @mouseup="endZoomAdd" />
            </div>

            <div v-if="isGif" class="vicp-range">
              <input v-model="fps" type="range" step="1" min="1" max="60">
              <i class="vicp-icon5" @mousedown="startFpsSub" @mouseup="endFpsSub" @mouseout="endFpsSub" />
              <i class="vicp-icon6" @mousedown="startFpsAdd" @mouseup="endFpsAdd" @mouseout="endFpsAdd" />
            </div>

            <div v-if="!noRotate" class="vicp-rotate">
              <i @mousedown="startRotateLeft" @mouseout="endRotate" @mouseup="endRotate">↺</i>
              <i @mousedown="startRotateRight" @mouseout="endRotate" @mouseup="endRotate">↻</i>
            </div>
          </div>
          <div v-show="true" class="vicp-crop-right">
            <div class="vicp-preview">
              <div v-if="!noSquare" class="vicp-preview-item">
                <img id="get_gif" :src="createImgUrl" :style="previewStyle">
                <span>{{ lang.preview }}</span>
              </div>
              <div v-if="!noCircle" class="vicp-preview-item vicp-preview-item-circle">
                <img :src="createImgUrl" :style="previewStyle">
                <span>{{ lang.preview }}</span>
              </div>
            </div>
          </div>
        </div>
        <div class="vicp-operate">
          <a @click="setStep(1)" @mousedown="ripple">{{ lang.btn.back }}</a>
          <a class="vicp-operate-btn" @click="prepareUpload" @mousedown="ripple">{{ lang.btn.save }}</a>
        </div>
      </div>

      <canvas v-show="false" id="canvas_use" ref="canvas" :width="width" :height="height" />
    </div>
  </div>
</template>

<script>
import request from '@/utils/request'
import language from './utils/language.js'
import mimes from './utils/mimes.js'
import data2blob from './utils/data2blob.js'
import effectRipple from './utils/effectRipple.js'
export default {
    props: {
        // 域，上传文件name，触发事件会带上（如果一个页面多个图片上传控件，可以做区分
        field: {
            type: String,
            'default': 'avatar'
        },
        // 原名key，类似于id，触发事件会带上（如果一个页面多个图片上传控件，可以做区分
        ki: {
            'default': 0
        },
        // 显示该控件与否
        value: {
            'default': true
        },
        // 上传地址
        url: {
            type: String,
            'default': ''
        },
        // 其他要上传文件附带的数据，对象格式
        params: {
            type: Object,
            'default': null
        },
        // Add custom headers
        headers: {
            type: Object,
            'default': null
        },
        // 剪裁图片的宽
        width: {
            type: Number,
            default: 200
        },
        // 剪裁图片的高
        height: {
            type: Number,
            default: 200
        },
        // 不显示旋转功能
        noRotate: {
            type: Boolean,
            default: false
        },
        // 不预览圆形图片
        noCircle: {
            type: Boolean,
            default: false
        },
        // 不预览方形图片
        noSquare: {
            type: Boolean,
            default: false
        },
        // 单文件大小限制
        maxSize: {
            type: Number,
            'default': 20480
        },
        // 语言类型
        langType: {
            type: String,
            'default': 'zh'
        },
        // 语言包
        langExt: {
            type: Object,
            'default': null
        },
        // 图片上传格式
        imgFormat: {
            type: String,
            'default': 'png'
        },
        // 是否支持跨域
        withCredentials: {
            type: Boolean,
            'default': false
        }
    },
    data() {
        const that = this
        const {
            imgFormat,
            langType,
            langExt,
            width,
            height
        } = that
        let isSupported = true
        const allowImgFormat = [
            'jpg',
            'png'
        ]
        const tempImgFormat = allowImgFormat.indexOf(imgFormat) === -1 ? 'png' : imgFormat
        const lang = language[langType] ? language[langType] : language['en']
        const mime = mimes[tempImgFormat]
        // 规范图片格式
        that.imgFormat = tempImgFormat
        if (langExt) {
            Object.assign(lang, langExt)
        }
        if (typeof FormData !== 'function') {
            isSupported = false
        }
        return {
            // 加载
            fullscreenLoading: false,
            // 上传文件
            files: null,
            // 图片的mime
            mime,
            // 语言包
            lang,
            // 浏览器是否支持该控件
            isSupported,
            // 浏览器是否支持触屏事件
            isSupportTouch: document.hasOwnProperty('ontouchstart'),
            // 步骤
            step: 1, // 1选择文件 2剪裁 3上传
            // 上传状态及进度
            loading: 0, // 0未开始 1正在 2成功 3错误
            progress: 0,
            // 是否有错误及错误信息
            hasError: false,
            errorMsg: '',
            // 需求图宽高比
            ratio: width / height,
            // 原图地址、生成图片地址
            sourceImg: null,
            sourceImgUrl: '',
            createImgUrl: '',
            // 原图片拖动事件初始值
            sourceImgMouseDown: {
                on: false,
                mX: 0, // 鼠标按下的坐标
                mY: 0,
                x: 0, // scale原图坐标
                y: 0
            },
            // 生成图片预览的容器大小
            previewContainer: {
                width: 100,
                height: 100
            },
            // 原图容器宽高
            sourceImgContainer: { // sic
                width: 240,
                height: 184 // 如果生成图比例与此一致会出现bug，先改成特殊的格式吧，哈哈哈
            },
            // 原图展示属性
            scale: {
                zoomFpsDown: false, // gif显示速度
                zoomFpsOn: false, // gif显示速度
                zoomAddOn: false, // 按钮缩放事件开启
                zoomSubOn: false, // 按钮缩放事件开启
                range: 1, // 最大100
                rotateLeft: false, // 按钮向左旋转事件开启
                rotateRight: false, // 按钮向右旋转事件开启
                degree: 0, // 旋转度数
                x: 0,
                y: 0,
                width: 0,
                height: 0,
                maxWidth: 0,
                maxHeight: 0,
                minWidth: 0, // 最宽
                minHeight: 0,
                naturalWidth: 0, // 原宽
                naturalHeight: 0
            },
            img_list: [],
            // gif 默认显示速度
            fps: 25,
            isGif: false
        }
    },
    computed: {
        // 播放速度
        runTime() {
            return 1000 / this.fps
        },
        // 原图样式
        sourceImgStyle() {
            const {
                scale,
                sourceImgMasking
            } = this
            const top = scale.y + sourceImgMasking.y + 'px'
            const left = scale.x + sourceImgMasking.x + 'px'
            return {
                top,
                left,
                width: scale.width + 'px',
                height: scale.height + 'px',
                transform: 'rotate(' + scale.degree + 'deg)', // 旋转时 左侧原始图旋转样式
                '-ms-transform': 'rotate(' + scale.degree + 'deg)', // 兼容IE9
                '-moz-transform': 'rotate(' + scale.degree + 'deg)', // 兼容FireFox
                '-webkit-transform': 'rotate(' + scale.degree + 'deg)', // 兼容Safari 和 chrome
                '-o-transform': 'rotate(' + scale.degree + 'deg)' // 兼容 Opera
            }
        },
        // 原图蒙版属性
        sourceImgMasking() {
            const {
                width,
                height,
                ratio,
                sourceImgContainer
            } = this
            const sic = sourceImgContainer
            const sicRatio = sic.width / sic.height // 原图容器宽高比
            let x = 0
            let y = 0
            let w = sic.width
            let h = sic.height
            let scale = 1
            if (ratio < sicRatio) {
                scale = sic.height / height
                w = sic.height * ratio
                x = (sic.width - w) / 2
            }
            if (ratio > sicRatio) {
                scale = sic.width / width
                h = sic.width / ratio
                y = (sic.height - h) / 2
            }
            return {
                scale, // 蒙版相对需求宽高的缩放
                x,
                y,
                width: w,
                height: h
            }
        },
        // 原图遮罩样式
        sourceImgShadeStyle() {
            const {
                sourceImgMasking,
                sourceImgContainer
            } = this
            const sic = sourceImgContainer
            const sim = sourceImgMasking
            const w = sim.width == sic.width ? sim.width : (sic.width - sim.width) / 2
            const h = sim.height == sic.height ? sim.height : (sic.height - sim.height) / 2
            return {
                width: w + 'px',
                height: h + 'px'
            }
        },
        previewStyle() {
            const {
                width,
                height,
                ratio,
                previewContainer
            } = this
            const pc = previewContainer
            let w = pc.width
            let h = pc.height
            const pcRatio = w / h
            if (ratio < pcRatio) {
                w = pc.height * ratio
            }
            if (ratio > pcRatio) {
                h = pc.width / ratio
            }
            return {
                width: w + 'px',
                height: h + 'px'
            }
        }
    },
    watch: {
        value(newValue) {
            if (newValue && this.loading != 1) {
                this.reset()
            }
        }
    },
    created() {
        // 绑定按键esc隐藏此插件事件
        document.addEventListener('keyup', this.closeHandler)
    },
    destroyed() {
        document.removeEventListener('keyup', this.closeHandler)
    },
    methods: {
        // 点击波纹效果
        ripple(e) {
            effectRipple(e)
        },
        // 关闭控件
        off() {
            setTimeout(() => {
                this.$emit('input', false)
                this.$emit('close1')
                if (this.step == 3 && this.loading == 2) {
                    this.setStep(1)
                }
            }, 200)
        },
        // 设置步骤
        setStep(no) {
            // 延时是为了显示动画效果呢，哈哈哈
            setTimeout(() => {
                this.step = no
            }, 200)
        },
        /* 图片选择区域函数绑定
             ---------------------------------------------------------------*/
        preventDefault(e) {
            e.preventDefault()
            return false
        },
        handleClick(e) {
            if (this.loading !== 1) {
                if (e.target !== this.$refs.fileinput) {
                    e.preventDefault()
                    if (document.activeElement !== this.$refs) {
                        this.$refs.fileinput.click()
                    }
                }
            }
        },
        handleChange(e) {
            this.fullscreenLoading = true
            e.preventDefault()
            if (this.loading !== 1) {
                const files = e.target.files || e.dataTransfer.files
                this.files = files
                this.reset()
                if (this.checkFile(files[0])) {
                    if (files[0].type === 'image/gif') {
                        this.isGif = true
                        this.pre_load_gif(files[0])
                    } else {
                        this.setSourceImg(files[0])
                    }
                }
            }
        },
        // gif图片拆解
        // 将canvas转换成file对象
        convertCanvasToImage(canvas) {
            return canvas.toDataURL('image/png', 1)
        },
        pre_load_gif(gif_source) {
            const gifImg = document.createElement('img')
            // gif库需要img标签配置下面两个属性
            gifImg.setAttribute('rel:animated_src', URL.createObjectURL(gif_source))
            gifImg.setAttribute('rel:auto_play', '0')
            document.getElementById('canvas_use').appendChild(gifImg)
            // 新建gif实例
            var rub = new SuperGif({ gif: gifImg })
            rub.load(() => {
                const img_list = []
                for (let i = 1; i <= rub.get_length(); i++) {
                    // 遍历gif实例的每一帧
                    rub.move_to(i)
                    // 将每一帧的canvas转换成file对象
                    const cur_file = this.convertCanvasToImage(rub.get_canvas(), gif_source.name.replace('.gif', '') + `-${i}`)
                    img_list.push(cur_file)
                }
                this.img_list = img_list
                this.setStep(2)
                let i = 0
                setTimeout(() => {
                    this.sourceImgUrl = this.img_list[i]
                    this.startCrop()
                    const a = () => {
                        setTimeout(async() => {
                            await new Promise((resolve) => {
                                i = i < this.img_list.length - 1 ? i + 1 : 0
                                this.sourceImgUrl = this.img_list[i]
                                this.sourceImg.src = this.img_list[i]
                                resolve()
                            })
                            await this.createImg().then(() => {
                                a()
                            })
                        }, this.runTime)
                    }
                    a()
                }, 500)
            })
        },
        /* ---------------------------------------------------------------*/
        // 检测选择的文件是否合适
        checkFile(file) {
            const that = this
            const {
                lang,
                maxSize
            } = that
            // 仅限图片
            if (file.type.indexOf('image') === -1) {
                that.hasError = true
                that.errorMsg = lang.error.onlyImg
                return false
            }
            // 超出大小
            if (file.size / 1024 > maxSize) {
                that.hasError = true
                that.errorMsg = lang.error.outOfSize + maxSize + 'kb'
                return false
            }
            return true
        },
        // 重置控件
        reset() {
            const that = this
            that.loading = 0
            that.hasError = false
            that.errorMsg = ''
            that.progress = 0
        },
        // 设置图片源
        setSourceImg(file) {
            const that = this
            const fr = new FileReader()
            fr.onload = function(e) {
                that.sourceImgUrl = fr.result
                that.startCrop()
            }
            fr.readAsDataURL(file)
        },
        // 剪裁前准备工作
        startCrop() {
            const that = this
            const {
                width,
                height,
                ratio,
                scale,
                sourceImgUrl,
                sourceImgMasking,
                lang
            } = that
            const sim = sourceImgMasking
            const img = new Image()
            img.src = sourceImgUrl
            img.onload = function() {
                const nWidth = img.naturalWidth
                const nHeight = img.naturalHeight
                const nRatio = nWidth / nHeight
                let w = sim.width
                let h = sim.height
                let x = 0
                let y = 0
                // 图片像素不达标
                if (nWidth < width || nHeight < height) {
                    that.hasError = true
                    that.errorMsg = lang.error.lowestPx + width + '*' + height
                    that.fullscreenLoading = false
                    that.setStep(1)
                    return false
                }
                if (ratio > nRatio) {
                    h = w / nRatio
                    y = (sim.height - h) / 2
                }
                if (ratio < nRatio) {
                    w = h * nRatio
                    x = (sim.width - w) / 2
                }
                scale.range = 0
                scale.x = x
                scale.y = y
                scale.width = w
                scale.height = h
                scale.degree = 0
                scale.minWidth = w
                scale.minHeight = h
                scale.maxWidth = nWidth * sim.scale
                scale.maxHeight = nHeight * sim.scale
                scale.naturalWidth = nWidth
                scale.naturalHeight = nHeight
                that.sourceImg = img
                that.createImg()
                that.fullscreenLoading = false
                that.setStep(2)
                img.onload = function() {}
            }
        },
        // 鼠标按下图片准备移动
        imgStartMove(e) {
            e.preventDefault()
            // 支持触摸事件，则鼠标事件无效
            if (this.isSupportTouch && !e.targetTouches) {
                return false
            }
            const et = e.targetTouches ? e.targetTouches[0] : e
            const {
                sourceImgMouseDown,
                scale
            } = this
            const simd = sourceImgMouseDown
            simd.mX = et.screenX
            simd.mY = et.screenY
            simd.x = scale.x
            simd.y = scale.y
            simd.on = true
        },
        // 鼠标按下状态下移动，图片移动
        imgMove(e) {
            e.preventDefault()
            // 支持触摸事件，则鼠标事件无效
            if (this.isSupportTouch && !e.targetTouches) {
                return false
            }
            const et = e.targetTouches ? e.targetTouches[0] : e
            const {
                sourceImgMouseDown: {
                    on,
                    mX,
                    mY,
                    x,
                    y
                },
                scale,
                sourceImgMasking
            } = this
            const sim = sourceImgMasking
            const nX = et.screenX
            const nY = et.screenY
            const dX = nX - mX
            const dY = nY - mY
            let rX = x + dX
            let rY = y + dY
            if (!on) return
            if (rX > 0) {
                rX = 0
            }
            if (rY > 0) {
                rY = 0
            }
            if (rX < sim.width - scale.width) {
                rX = sim.width - scale.width
            }
            if (rY < sim.height - scale.height) {
                rY = sim.height - scale.height
            }
            scale.x = rX
            scale.y = rY
        },
        // 按钮按下开始向右旋转
        startRotateRight(e) {
            const that = this
            const {
                scale
            } = that
            scale.rotateRight = true
            function rotate() {
                if (scale.rotateRight) {
                    const degree = ++scale.degree
                    that.createImg(degree)
                    setTimeout(function() {
                        rotate()
                    }, 60)
                }
            }
            rotate()
        },
        // 按钮按下开始向右旋转
        startRotateLeft(e) {
            const that = this
            const {
                scale
            } = that
            scale.rotateLeft = true
            function rotate() {
                if (scale.rotateLeft) {
                    const degree = --scale.degree
                    that.createImg(degree)
                    setTimeout(function() {
                        rotate()
                    }, 60)
                }
            }
            rotate()
        },
        // 停止旋转
        endRotate() {
            const {
                scale
            } = this
            scale.rotateLeft = false
            scale.rotateRight = false
        },
        // 按钮按下开始放大
        startZoomAdd(e) {
            const that = this
            const {
                scale
            } = that
            scale.zoomAddOn = true
            function zoom() {
                if (scale.zoomAddOn) {
                    const range = scale.range >= 100 ? 100 : ++scale.range
                    that.zoomImg(range)
                    setTimeout(function() {
                        zoom()
                    }, 60)
                }
            }
            zoom()
        },
        // 按钮松开或移开取消放大
        endZoomAdd(e) {
            this.scale.zoomAddOn = false
        },
        // 按钮按下开始缩小
        startZoomSub(e) {
            const that = this
            const {
                scale
            } = that
            scale.zoomSubOn = true
            function zoom() {
                if (scale.zoomSubOn) {
                    const range = scale.range <= 0 ? 0 : --scale.range
                    that.zoomImg(range)
                    setTimeout(function() {
                        zoom()
                    }, 60)
                }
            }
            zoom()
        },
        // 按钮松开或移开取消缩小
        endZoomSub(e) {
            const {
                scale
            } = this
            scale.zoomSubOn = false
        },
        zoomChange(e) {
            this.zoomImg(e.target.value)
        },
        endFpsSub() {
            const {
                scale
            } = this
            scale.zoomFpsDown = false
        },
        endFpsAdd() {
            const {
                scale
            } = this
            scale.zoomFpsOn = false
        },
        // 按钮按下开始增加
        startFpsAdd(e) {
            const that = this
            const {
                scale
            } = that
            scale.zoomFpsOn = true
            function zoom() {
                if (scale.zoomFpsOn) {
                    that.fps = that.fps >= 60 ? 60 : ++that.fps
                    setTimeout(function() {
                        zoom()
                    }, 60)
                }
            }
            zoom()
        },
        // 按钮按下开始减少
        startFpsSub(e) {
            const that = this
            const {
                scale
            } = that
            scale.zoomFpsDown = true
            function zoom() {
                if (scale.zoomFpsDown) {
                    that.fps = that.fps <= 1 ? 1 : --that.fps
                    setTimeout(function() {
                        zoom()
                    }, 60)
                }
            }
            zoom()
        },
        // 缩放原图
        zoomImg(newRange) {
            const that = this
            const {
                sourceImgMasking,
                sourceImgMouseDown,
                scale
            } = this
            const {
                maxWidth,
                maxHeight,
                minWidth,
                minHeight,
                width,
                height,
                x,
                y,
                range
            } = scale
            const sim = sourceImgMasking
            // 蒙版宽高
            const sWidth = sim.width
            const sHeight = sim.height
            // 新宽高
            const nWidth = minWidth + (maxWidth - minWidth) * newRange / 100
            const nHeight = minHeight + (maxHeight - minHeight) * newRange / 100
            // 新坐标（根据蒙版中心点缩放）
            let nX = sWidth / 2 - (nWidth / width) * (sWidth / 2 - x)
            let nY = sHeight / 2 - (nHeight / height) * (sHeight / 2 - y)
            // 判断新坐标是否超过蒙版限制
            if (nX > 0) {
                nX = 0
            }
            if (nY > 0) {
                nY = 0
            }
            if (nX < sWidth - nWidth) {
                nX = sWidth - nWidth
            }
            if (nY < sHeight - nHeight) {
                nY = sHeight - nHeight
            }
            // 赋值处理
            scale.x = nX
            scale.y = nY
            scale.width = nWidth
            scale.height = nHeight
            scale.range = newRange
            setTimeout(function() {
                if (scale.range == newRange) {
                    that.createImg()
                }
            }, 300)
        },
        // 生成需求图片
        createImg(e) {
            return new Promise((resolve) => {
                const that = this
                const {
                    mime,
                    sourceImg,
                    scale: {
                        x,
                        y,
                        width,
                        height,
                        degree
                    },
                    sourceImgMasking: {
                        scale
                    }
                } = that
                const canvas = document.getElementById('canvas_use')
                if (!canvas) {
                    return
                }
                const ctx = canvas.getContext('2d')
                if (e) {
                    // 取消鼠标按下移动状态
                    that.sourceImgMouseDown.on = false
                }
                canvas.width = that.width
                canvas.height = that.height
                ctx.clearRect(0, 0, that.width, that.height)
                // 将透明区域设置为白色底边
                ctx.fillStyle = '#fff'
                ctx.fillRect(0, 0, that.width, that.height)
                ctx.translate(that.width * 0.5, that.height * 0.5)
                ctx.rotate(Math.PI * degree / 180)
                ctx.translate(-that.width * 0.5, -that.height * 0.5)
                ctx.drawImage(sourceImg, x / scale, y / scale, width / scale, height / scale)
                that.createImgUrl = canvas.toDataURL(mime)
                resolve()
            })
        },
        prepareUpload() {
            this.fullscreenLoading = true
            const _this = this
            if (this.isGif) {
                var gif = new GIF({
                    workers: 2, // 启用两个worker。
                    quality: 10// 图像质量
                })// 创建一个GIF实例
                let i = 0
                const run = () => {
                    setTimeout(() => {
                        if (i < this.img_list.length - 1) {
                            i++
                            run()
                            gif.addFrame(document.getElementById('canvas_use'), { delay: this.runTime * 4 / 3, copy: true })
                        } else {
                            gif.render()// 开始启动
                            gif.on('finished', function(blob) { // 最后生成一个blob对象
                                _this.$emit('fileSend', URL.createObjectURL(blob), new window.File(
                                    [blob],
                                    _this.files[0].name,
                                    { type: _this.files[0].type }
                                ))
                                this.fullscreenLoading = false
                                _this.$emit('close1')
                            })
                        }
                    }, this.runTime)
                }
                run()
            } else {
                const {
                    url,
                    createImgUrl,
                    field,
                    ki,
                    mime,
                    imgFormat
                } = this
                this.$emit('fileSend', this.createImgUrl, data2blob(createImgUrl, mime), field + '.' + imgFormat)
                this.fullscreenLoading = false
                this.$emit('close1')
            }
        },
        // 上传图片
        upload() {
            const that = this
            const {
                lang,
                imgFormat,
                mime,
                url,
                params,
                headers,
                field,
                ki,
                createImgUrl,
                withCredentials
            } = this
            const fmData = new FormData()
            fmData.append(field, data2blob(createImgUrl, mime), field + '.' + imgFormat)
            // 添加其他参数
            if (typeof params === 'object' && params) {
                Object.keys(params).forEach((k) => {
                    fmData.append(k, params[k])
                })
            }
            // 监听进度回调
            const uploadProgress = function(event) {
                if (event.lengthComputable) {
                    that.progress = 100 * Math.round(event.loaded) / event.total
                }
            }
            // 上传文件
            that.reset()
            that.loading = 1
            that.setStep(3)
            request({
                url,
                method: 'post',
                data: fmData
            }).then(resData => {
                that.loading = 2
                that.$emit('crop-upload-success', resData.data)
            }).catch(err => {
                if (that.value) {
                    that.loading = 3
                    that.hasError = true
                    that.errorMsg = lang.fail
                    that.$emit('crop-upload-fail', err, field, ki)
                }
            })
        },
        closeHandler(e) {
            if (this.value && (e.key == 'Escape' || e.keyCode == 27)) {
                this.off()
            }
        }
    }
}
</script>

<!--
<style lang='sass' src="./scss/upload.scss">
</style> -->

<style scoped>
  @-webkit-keyframes vicp_progress {
    0% {
      background-position-y: 0; }
    100% {
      background-position-y: 40px; } }
  @keyframes vicp_progress {
    0% {
      background-position-y: 0; }
    100% {
      background-position-y: 40px; } }
  @-webkit-keyframes vicp {
    0% {
      opacity: 0;
      -webkit-transform: scale(0) translatey(-60px);
      transform: scale(0) translatey(-60px); }
    100% {
      opacity: 1;
      -webkit-transform: scale(1) translatey(0);
      transform: scale(1) translatey(0); } }
  @keyframes vicp {
    0% {
      opacity: 0;
      -webkit-transform: scale(0) translatey(-60px);
      transform: scale(0) translatey(-60px); }
    100% {
      opacity: 1;
      -webkit-transform: scale(1) translatey(0);
      transform: scale(1) translatey(0); } }
  .slider_class{

  }
  .vue-image-crop-upload {
    position: fixed;
    display: block;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    z-index: 10000;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.65);
    -webkit-tap-highlight-color: transparent;
    -moz-tap-highlight-color: transparent; }
  .vue-image-crop-upload .vicp-wrap {
    -webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
    box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
    position: fixed;
    display: block;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    z-index: 10000;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    margin: auto;
    width: 600px;
    height: 330px;
    padding: 25px;
    background-color: #fff;
    border-radius: 2px;
    -webkit-animation: vicp 0.12s ease-in;
    animation: vicp 0.12s ease-in; }
  .vue-image-crop-upload .vicp-wrap .vicp-close {
    position: absolute;
    right: -30px;
    top: -30px; }
  .vue-image-crop-upload .vicp-wrap .vicp-close .vicp-icon4 {
    position: relative;
    display: block;
    width: 30px;
    height: 30px;
    cursor: pointer;
    -webkit-transition: -webkit-transform 0.18s;
    transition: -webkit-transform 0.18s;
    transition: transform 0.18s;
    transition: transform 0.18s, -webkit-transform 0.18s;
    -webkit-transform: rotate(0);
    -ms-transform: rotate(0);
    transform: rotate(0); }
  .vue-image-crop-upload .vicp-wrap .vicp-close .vicp-icon4::after, .vue-image-crop-upload .vicp-wrap .vicp-close .vicp-icon4::before {
    -webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
    box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
    content: '';
    position: absolute;
    top: 12px;
    left: 4px;
    width: 20px;
    height: 3px;
    -webkit-transform: rotate(45deg);
    -ms-transform: rotate(45deg);
    transform: rotate(45deg);
    background-color: #fff; }
  .vue-image-crop-upload .vicp-wrap .vicp-close .vicp-icon4::after {
    -webkit-transform: rotate(-45deg);
    -ms-transform: rotate(-45deg);
    transform: rotate(-45deg); }
  .vue-image-crop-upload .vicp-wrap .vicp-close .vicp-icon4:hover {
    -webkit-transform: rotate(90deg);
    -ms-transform: rotate(90deg);
    transform: rotate(90deg); }
  .vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area {
    position: relative;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    padding: 35px;
    height: 170px;
    background-color: rgba(0, 0, 0, 0.03);
    text-align: center;
    border: 1px dashed rgba(0, 0, 0, 0.08);
    overflow: hidden; }
  .vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-icon1 {
    display: block;
    margin: 0 auto 6px;
    width: 42px;
    height: 42px;
    overflow: hidden; }
  .vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-icon1 .vicp-icon1-arrow {
    display: block;
    margin: 0 auto;
    width: 0;
    height: 0;
    border-bottom: 14.7px solid rgba(0, 0, 0, 0.3);
    border-left: 14.7px solid transparent;
    border-right: 14.7px solid transparent; }
  .vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-icon1 .vicp-icon1-body {
    display: block;
    width: 12.6px;
    height: 14.7px;
    margin: 0 auto;
    background-color: rgba(0, 0, 0, 0.3); }
  .vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-icon1 .vicp-icon1-bottom {
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    display: block;
    height: 12.6px;
    border: 6px solid rgba(0, 0, 0, 0.3);
    border-top: none; }
  .vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-hint {
    display: block;
    padding: 15px;
    font-size: 14px;
    color: #666;
    line-height: 30px; }
  .vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-no-supported-hint {
    display: block;
    position: absolute;
    top: 0;
    left: 0;
    padding: 30px;
    width: 100%;
    height: 60px;
    line-height: 30px;
    background-color: #eee;
    text-align: center;
    color: #666;
    font-size: 14px; }
  .vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area:hover {
    cursor: pointer;
    border-color: rgba(0, 0, 0, 0.1);
    background-color: rgba(0, 0, 0, 0.05); }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop {
    overflow: hidden; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left {
    float: left; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-img-container {
    position: relative;
    display: block;
    width: 240px;
    height: 180px;
    background-color: #e5e5e0;
    overflow: hidden; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-img-container .vicp-img {
    position: absolute;
    display: block;
    cursor: move;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-img-container .vicp-img-shade {
    -webkit-box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
    box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
    position: absolute;
    background-color: rgba(241, 242, 243, 0.8); }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-img-container .vicp-img-shade.vicp-img-shade-1 {
    top: 0;
    left: 0; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-img-container .vicp-img-shade.vicp-img-shade-2 {
    bottom: 0;
    right: 0; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-rotate {
    position: relative;
    width: 240px;
    height: 18px; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-rotate i {
    display: block;
    width: 18px;
    height: 18px;
    border-radius: 100%;
    line-height: 18px;
    text-align: center;
    font-size: 12px;
    font-weight: bold;
    background-color: rgba(0, 0, 0, 0.08);
    color: #fff;
    overflow: hidden; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-rotate i:hover {
    -webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
    box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
    cursor: pointer;
    background-color: rgba(0, 0, 0, 0.14); }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-rotate i:first-child {
    float: left; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-rotate i:last-child {
    float: right; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range {
    position: relative;
    margin: 15px 0 10px 0;
    width: 240px;
    height: 18px; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon5,
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon6 {
    position: absolute;
    top: 0;
    width: 18px;
    height: 18px;
    border-radius: 100%;
    background-color: rgba(0, 0, 0, 0.08); }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon5:hover,
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon6:hover {
    -webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
    box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
    cursor: pointer;
    background-color: rgba(0, 0, 0, 0.14); }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon5 {
    left: 0; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon5::before {
    position: absolute;
    content: '';
    display: block;
    left: 3px;
    top: 8px;
    width: 12px;
    height: 2px;
    background-color: #fff; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon6 {
    right: 0; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon6::before {
    position: absolute;
    content: '';
    display: block;
    left: 3px;
    top: 8px;
    width: 12px;
    height: 2px;
    background-color: #fff; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon6::after {
    position: absolute;
    content: '';
    display: block;
    top: 3px;
    left: 8px;
    width: 2px;
    height: 12px;
    background-color: #fff; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range] {
    display: block;
    padding-top: 5px;
    margin: 0 auto;
    width: 180px;
    height: 8px;
    vertical-align: top;
    background: transparent;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    cursor: pointer;
    /* 滑块
       ---------------------------------------------------------------*/
    /* 轨道
       ---------------------------------------------------------------*/ }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:focus {
    outline: none; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-webkit-slider-thumb {
    -webkit-box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
    box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
    -webkit-appearance: none;
    appearance: none;
    margin-top: -3px;
    width: 12px;
    height: 12px;
    background-color: #61c091;
    border-radius: 100%;
    border: none;
    -webkit-transition: 0.2s;
    transition: 0.2s; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-moz-range-thumb {
    box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
    -moz-appearance: none;
    appearance: none;
    width: 12px;
    height: 12px;
    background-color: #61c091;
    border-radius: 100%;
    border: none;
    -webkit-transition: 0.2s;
    transition: 0.2s; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-ms-thumb {
    box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
    appearance: none;
    width: 12px;
    height: 12px;
    background-color: #61c091;
    border: none;
    border-radius: 100%;
    -webkit-transition: 0.2s;
    transition: 0.2s; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:active::-moz-range-thumb {
    box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
    width: 14px;
    height: 14px; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:active::-ms-thumb {
    box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
    width: 14px;
    height: 14px; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:active::-webkit-slider-thumb {
    -webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
    box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
    margin-top: -4px;
    width: 14px;
    height: 14px; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-webkit-slider-runnable-track {
    -webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
    box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
    width: 100%;
    height: 6px;
    cursor: pointer;
    border-radius: 2px;
    border: none;
    background-color: rgba(68, 170, 119, 0.3); }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-moz-range-track {
    box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
    width: 100%;
    height: 6px;
    cursor: pointer;
    border-radius: 2px;
    border: none;
    background-color: rgba(68, 170, 119, 0.3); }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-ms-track {
    box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
    width: 100%;
    cursor: pointer;
    background: transparent;
    border-color: transparent;
    color: transparent;
    height: 6px;
    border-radius: 2px;
    border: none; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-ms-fill-lower {
    background-color: rgba(68, 170, 119, 0.3); }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-ms-fill-upper {
    background-color: rgba(68, 170, 119, 0.15); }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:focus::-webkit-slider-runnable-track {
    background-color: rgba(68, 170, 119, 0.5); }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:focus::-moz-range-track {
    background-color: rgba(68, 170, 119, 0.5); }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:focus::-ms-fill-lower {
    background-color: rgba(68, 170, 119, 0.45); }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:focus::-ms-fill-upper {
    background-color: rgba(68, 170, 119, 0.25); }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right {
    float: right; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right .vicp-preview {
    height: 150px;
    overflow: hidden; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right .vicp-preview .vicp-preview-item {
    position: relative;
    padding: 5px;
    width: 100px;
    height: 100px;
    float: left;
    margin-right: 16px; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right .vicp-preview .vicp-preview-item span {
    position: absolute;
    bottom: -30px;
    width: 100%;
    font-size: 14px;
    color: #bbb;
    display: block;
    text-align: center; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right .vicp-preview .vicp-preview-item img {
    position: absolute;
    display: block;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    margin: auto;
    padding: 3px;
    background-color: #fff;
    border: 1px solid rgba(0, 0, 0, 0.15);
    overflow: hidden;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right .vicp-preview .vicp-preview-item.vicp-preview-item-circle {
    margin-right: 0; }
  .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right .vicp-preview .vicp-preview-item.vicp-preview-item-circle img {
    border-radius: 100%; }
  .vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload {
    position: relative;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    padding: 35px;
    height: 170px;
    background-color: rgba(0, 0, 0, 0.03);
    text-align: center;
    border: 1px dashed #ddd; }
  .vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-loading {
    display: block;
    padding: 15px;
    font-size: 16px;
    color: #999;
    line-height: 30px; }
  .vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-progress-wrap {
    margin-top: 12px;
    background-color: rgba(0, 0, 0, 0.08);
    border-radius: 3px; }
  .vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-progress-wrap .vicp-progress {
    position: relative;
    display: block;
    height: 5px;
    border-radius: 3px;
    background-color: #4a7;
    -webkit-box-shadow: 0 2px 6px 0 rgba(68, 170, 119, 0.3);
    box-shadow: 0 2px 6px 0 rgba(68, 170, 119, 0.3);
    -webkit-transition: width 0.15s linear;
    transition: width 0.15s linear;
    background-image: -webkit-linear-gradient(135deg, rgba(255, 255, 255, 0.2) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0.2) 75%, transparent 75%, transparent);
    background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.2) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0.2) 75%, transparent 75%, transparent);
    background-size: 40px 40px;
    -webkit-animation: vicp_progress 0.5s linear infinite;
    animation: vicp_progress 0.5s linear infinite; }
  .vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-progress-wrap .vicp-progress::after {
    content: '';
    position: absolute;
    display: block;
    top: -3px;
    right: -3px;
    width: 9px;
    height: 9px;
    border: 1px solid rgba(245, 246, 247, 0.7);
    -webkit-box-shadow: 0 1px 4px 0 rgba(68, 170, 119, 0.7);
    box-shadow: 0 1px 4px 0 rgba(68, 170, 119, 0.7);
    border-radius: 100%;
    background-color: #4a7; }
  .vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-error,
  .vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-success {
    height: 100px;
    line-height: 100px; }
  .vue-image-crop-upload .vicp-wrap .vicp-operate {
    position: absolute;
    right: 20px;
    bottom: 20px; }
  .vue-image-crop-upload .vicp-wrap .vicp-operate a {
    position: relative;
    float: left;
    display: block;
    margin-left: 10px;
    width: 100px;
    height: 36px;
    line-height: 36px;
    text-align: center;
    cursor: pointer;
    font-size: 14px;
    color: #4a7;
    border-radius: 2px;
    overflow: hidden;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none; }
  .vue-image-crop-upload .vicp-wrap .vicp-operate a:hover {
    background-color: rgba(0, 0, 0, 0.03); }
  .vue-image-crop-upload .vicp-wrap .vicp-error,
  .vue-image-crop-upload .vicp-wrap .vicp-success {
    display: block;
    font-size: 14px;
    line-height: 24px;
    height: 24px;
    color: #d10;
    text-align: center;
    vertical-align: top; }
  .vue-image-crop-upload .vicp-wrap .vicp-success {
    color: #4a7; }
  .vue-image-crop-upload .vicp-wrap .vicp-icon3 {
    position: relative;
    display: inline-block;
    width: 20px;
    height: 20px;
    top: 4px; }
  .vue-image-crop-upload .vicp-wrap .vicp-icon3::after {
    position: absolute;
    top: 3px;
    left: 6px;
    width: 6px;
    height: 10px;
    border-width: 0 2px 2px 0;
    border-color: #4a7;
    border-style: solid;
    -webkit-transform: rotate(45deg);
    -ms-transform: rotate(45deg);
    transform: rotate(45deg);
    content: ''; }
  .vue-image-crop-upload .vicp-wrap .vicp-icon2 {
    position: relative;
    display: inline-block;
    width: 20px;
    height: 20px;
    top: 4px; }
  .vue-image-crop-upload .vicp-wrap .vicp-icon2::after, .vue-image-crop-upload .vicp-wrap .vicp-icon2::before {
    content: '';
    position: absolute;
    top: 9px;
    left: 4px;
    width: 13px;
    height: 2px;
    background-color: #d10;
    -webkit-transform: rotate(45deg);
    -ms-transform: rotate(45deg);
    transform: rotate(45deg); }
  .vue-image-crop-upload .vicp-wrap .vicp-icon2::after {
    -webkit-transform: rotate(-45deg);
    -ms-transform: rotate(-45deg);
    transform: rotate(-45deg); }
  .e-ripple {
    position: absolute;
    border-radius: 100%;
    background-color: rgba(0, 0, 0, 0.15);
    background-clip: padding-box;
    pointer-events: none;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    -webkit-transform: scale(0);
    -ms-transform: scale(0);
    transform: scale(0);
    opacity: 1; }
  .e-ripple.z-active {
    opacity: 0;
    -webkit-transform: scale(2);
    -ms-transform: scale(2);
    transform: scale(2);
    -webkit-transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
    transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
    transition: opacity 1.2s ease-out, transform 0.6s ease-out;
    transition: opacity 1.2s ease-out, transform 0.6s ease-out, -webkit-transform 0.6s ease-out; }
</style>
